Skip to content

v4#97

Merged
aaronbrezel merged 34 commits into
mainfrom
develop
May 7, 2026
Merged

v4#97
aaronbrezel merged 34 commits into
mainfrom
develop

Conversation

@aaronbrezel

Copy link
Copy Markdown
Member

Summary

Manual QA

Complete for PRs targeting main. Mark N/A with reason for PRs targeting develop.

  • Add-on menu appears after opening a Sheet
  • Sidebar opens without errors
  • Import Drive Links — imports files from a folder
  • Extract Text — extracts text from a Doc/PDF/image
  • Sample Rows — samples rows reproducibly with a seed
  • Run AI — batch inference completes and writes output column
  • Tested on a Sheet the tester does not own (shared access)

Notes

aaronbrezel and others added 30 commits March 27, 2026 10:49
Merge pull request #72 from propublica/develop
…stic ColumnDef[] system (#75)

* docs: add recipe prep redesign — design doc + implementation plan

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: replace named-field PrepRecipeParams/Result with agnostic ColStrategy shapes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: update stale JSDoc comments in shared/types.ts after PrepRecipeResult simplification

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: rewrite prepRecipe() to iterate PrepColSpec[] with two-pass folder scan

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: replace named-field RecipeParams with ColumnDef[] + RecipeSettings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: update google.d.ts prepRecipe return type, move ToolId import, update services test shapes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: migrate document-summarization recipe to ColumnDef[] shape

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: rewrite RecipePanel tests for ColumnDef[] shape (failing — panel rewrite in next task)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: consolidate recipes.ts imports, remove unused mount() return field, add empty-appendField test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: rewrite RecipePanel for ColumnDef[] — agnostic column specs, role-based RunConfig assembly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* style: apply Prettier formatting to recipe.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* style: fix Prettier formatting in server/index.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Exports CHUNK_SIZE (50) and computeChunks() from ConfigureAIRunPanel module so handleRun() can slice row ranges into fixed-size batches for chunked execution.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace single runBatchAI dispatch with a chunked async loop that shows
a confirmation dialog for large row counts and respects jobStore.isCancelled()
between chunks. Falls back to single dispatch when no explicit rowRange is set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…#77)

* feat: add cancelling to LoadingStatus

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add cancel, isCancelled, setProgress to JobStore

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add computeChunks helper with tests

Exports CHUNK_SIZE (50) and computeChunks() from ConfigureAIRunPanel module so handleRun() can slice row ranges into fixed-size batches for chunked execution.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: pre-flight warning and chunked dispatch in handleRun

Replace single runBatchAI dispatch with a chunked async loop that shows
a confirmation dialog for large row counts and respects jobStore.isCancelled()
between chunks. Falls back to single dispatch when no explicit rowRange is set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: inline runChunks IIFE and clarify chunk warning guard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: stop button and cancelling state in JobIndicator

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: escape double quotes in JobIndicator HTML attribute

* docs: add chunked batch execution design and implementation plan

* fix: prevent poll from overwriting cancelling state; reduce chunk size to 10; clarify cancel message

* feat: show global row range between chunks; surface row progress when cancelling

- Between-chunk progress now shows "Rows X–Y of Z" using sheet row numbers
  instead of abstract chunk numbers, giving users global context
- When cancelling, server polling message is passed through as
  "Stopping — {message}" so users can see how far the current chunk has to go
- Reduce CHUNK_SIZE to 10 rows for more responsive cancellation (was 50)
- Add test covering the "Stopping —" message passthrough behavior

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: hint in row range label that explicit range enables large-job features

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: move row range hint to sit next to "Specify range" radio option

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add cancelling to LoadingStatus

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add cancel, isCancelled, setProgress to JobStore

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add computeChunks helper with tests

Exports CHUNK_SIZE (50) and computeChunks() from ConfigureAIRunPanel module so handleRun() can slice row ranges into fixed-size batches for chunked execution.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: pre-flight warning and chunked dispatch in handleRun

Replace single runBatchAI dispatch with a chunked async loop that shows
a confirmation dialog for large row counts and respects jobStore.isCancelled()
between chunks. Falls back to single dispatch when no explicit rowRange is set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: inline runChunks IIFE and clarify chunk warning guard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: stop button and cancelling state in JobIndicator

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: escape double quotes in JobIndicator HTML attribute

* docs: add chunked batch execution design and implementation plan

* fix: address post-review issues from chunked batch execution feature

- setProgress() now guards against overwriting cancelling state
- Align cancel message wording: all cancelling messages use "Stopping — ..." prefix
- Extract chunk loop from handleRun() into private runChunks() method
- Document estimatedMins 5s/row assumption with inline comment
- Fix isCancelled test that was checking the wrong job ID; add dedicated
  test for cancel flag cleanup on job completion

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: replace SingleTagList/TagList column pickers with TokenInput

* feat: make new-column chip prefix configurable via newDefault option

  Add newDefault to TokenInputOpts so each panel can pre-fill the new-column
  chip with a contextually appropriate name. ai_ for AI output, extracted_text
  for Extract Text, drive_links for Import Drive Links.

  Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com
…igureAIRunPanel (#79)

* docs: add PromptColList UI design for ordered prompt column selection

* feat: add PromptColList component for ordered prompt column selection

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: clarify moveRow variable names in PromptColList

* feat: add pcol-* styles for PromptColList component

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: replace split TokenInput pickers with PromptColList in ConfigureAIRunPanel

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: update configure-ai-run tests for PromptColList

Replace old user-prompt-cols/drive-file-cols field ID helpers with new
addPromptCol/getPromptColValues helpers that interact with the PromptColList
component's .pcol-row/.pcol-add-btn DOM structure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: add PromptColList unit tests and implementation plan

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: add PromptColList UI design for ordered prompt column selection

* feat: reduce OAuth scopes to least-privilege for Drive access

  Replaces the broad `drive` scope with `drive.readonly` + `drive.file`,
  removing "edit and delete all your Google Drive files" from the consent
  screen. Adds user-facing auth model documentation and implementation
  design doc.

  Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* removing old auth model doc
Bumps [hono](https://github.com/honojs/hono) from 4.12.8 to 4.12.12.
- [Release notes](https://github.com/honojs/hono/releases)
- [Commits](honojs/hono@v4.12.8...v4.12.12)

---
updated-dependencies:
- dependency-name: hono
  dependency-version: 4.12.12
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* docs: add ConfigureAIRunPanel UX redesign design doc

* refactor: collapse PromptColList row to single inline line

* feat: reorder ConfigureAIRunPanel sections and add helper text

* fix: remove duplicate field-helper CSS rule

* feat: add collapsible Tools section to ConfigureAIRunPanel

* docs: add ConfigureAIRunPanel UX redesign implementation plan

* fix: prevent collapsible header overflow with min-width and box-sizing

* fix: prevent sidebar horizontal overflow from collapsible header and prompt row

* fix: prevent sidebar horizontal overflow from collapsible header and prompt row

* refactor: replace kind pills with cycling toggle in PromptColList

* feat: add cycle indicator to kind toggle and tighten row spacing

* feat: move Tools section above Rows to process

* feat: add divider lines between panel sections
* feat: prepend label to text parts in runInference when PromptInput.label is set

Also redirects Jest cache to project-local .jest-cache/ so commits work
in sandboxed environments.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add prefixWithColName to RunConfig and forward label in runBatchAI

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add prefixWithColName checkbox to ConfigureAIRunPanel

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs: add column label prefix design and implementation plan

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: move prefix checkbox under User Prompt Columns, shorten copy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Bumps [@hono/node-server](https://github.com/honojs/node-server) from 1.19.11 to 1.19.13.
- [Release notes](https://github.com/honojs/node-server/releases)
- [Commits](honojs/node-server@v1.19.11...v1.19.13)

---
updated-dependencies:
- dependency-name: "@hono/node-server"
  dependency-version: 1.19.13
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps  and [brace-expansion](https://github.com/juliangruber/brace-expansion). These dependencies needed to be updated together.

Updates `brace-expansion` from 1.1.12 to 1.1.13
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](juliangruber/brace-expansion@v1.1.12...v1.1.13)

Updates `brace-expansion` from 5.0.3 to 5.0.5
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](juliangruber/brace-expansion@v1.1.12...v1.1.13)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 1.1.13
  dependency-type: indirect
- dependency-name: brace-expansion
  dependency-version: 5.0.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…mplate (#87)

* feat: add interpolateTemplate utility for recipe template strategy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: update ColStrategy and PrepRecipeParams for inputId-based binding

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: update prepRecipe to resolve inputId refs and handle template strategy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: replace ColumnDef cluster with UserInput; update RecipeDefinition

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: update recipes-list nav and services test for new RecipeDefinition and PrepRecipeParams shapes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: rewrite RecipePanel to render UserInput[] and use prepTemplate/runTemplate

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: rewrite RECIPES registry under new RecipeDefinition shape

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: prettier format utils.ts; add recipe redesign impl plan doc

* adding planning doc

* refactor: rename ColStrategy→FillStrategy and strategy→fillStrategy

Consistent naming across all layers: the discriminated union is now
FillStrategy (it describes how a column gets filled at prep time) and
the field on PrepColSpec is fillStrategy. No behaviour change.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: derive RunConfig from column roles, drop runTemplate

Each PrepColSpec now carries an optional role (file-prompt, text-prompt,
system-prompt, output). RecipePanel builds the column-referencing parts of
RunConfig via buildRunTemplate() instead of reading a manually-written
runTemplate. Non-column AI settings move to RecipeDefinition.settings.

RecipeDefinition.runTemplate removed — column titles now exist in exactly
one place.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: simplify ColumnRole to string union, RecipeSettings to Pick

ColumnRole had no payload on any variant — the object wrapper was
unnecessary ceremony. Now a plain string union.

RecipeSettings is now Pick<RunConfig, ...> so it tracks RunConfig
automatically instead of duplicating field declarations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: split PrepColSpec/RecipeColumn, rename UserInput→RecipeInput

PrepColSpec (shared RPC type) no longer carries role — the server never
reads it. RecipeColumn extends PrepColSpec client-side and adds role,
keeping ColumnRole out of the RPC boundary.

UserInput renamed to RecipeInput to make its scope explicit — it's
a recipe-specific concept, not a generic form primitive.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add conditional block syntax to interpolateTemplate

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: add same-key block test; docs: note nesting unsupported

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: update document-summarization recipe for journalism use

* test: integration tests for recipe template rendering

* docs: add design and implementation plan for document summarization recipe redesign

* feat: remove redundant User Prompt column from document-summarization recipe

* feat: apply field-label styling and (optional) markers to recipe inputs

* feat: use field-group wrapper for recipe inputs to get section dividers

* feat: add intro field to RecipeDefinition for panel-level description

* fix: remove redundant optional field guidance from recipe intro

* tweaking helper text

* fix: remove BLUF label prefix from system prompt structure guideline

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…#90)

- Add TokenInput and PromptColList to CLAUDE.md component graph
- Add Recipe System section to CLAUDE.md (RecipeDefinition shape,
  RecipeColumn.role, FillStrategy kinds including template syntax,
  RecipeInput.id naming constraint)
- Fix stale recipe propagation path in Tool System section (server no
  longer echoes back RunConfig; preppedRunConfig is assembled client-side)
- Add RunConfig / PromptColumnSpec section to architecture.md
- Fix google.d.ts description to clarify only client-callable functions
  need declarations, not every server function
- Update architecture.md recipes description to match new RecipeDefinition
  shape and correct preppedRunConfig assembly flow

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
)

* feat: improve empty-state message in Run AI panel with recipes link

Replaces the terse "No columns found" message with copy that points
users to Recipes as a starting point, and wires a click handler to
navigate directly to the recipes list.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* tweaking helper text

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
jfrankl and others added 4 commits April 22, 2026 09:34
Make the typefaces better match Google Sheets.
Documents font size tokens, font-family rule for form elements, and
preferred color variables introduced in the #92 style standardization PR.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: AI processing redesign — parallel real-time and async batch paths

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs: add Phase 1 + Phase 2 AI processing redesign design docs

Phase 1 spec covers parallel fetchAll pipeline, Files API integration,
and inference.ts refactor. Phase 2 notes park the async batch API design
for a future planning session.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs: add Phase 1 parallel inference pipeline implementation plan

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add callGeminiAPIBatch for parallel Gemini inference

* feat: add fetchDriveMetadata and downloadDriveFiles for parallel Drive access

* feat: add uploadFilesToGemini for Gemini Files API integration

Implements parallel file upload to the Gemini Files API using
UrlFetchApp.fetchAll with multipart/related encoding, batched in groups
of 10 to limit peak memory pressure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: extract buildInferenceRequest from runInference for batch path

Splits the request-building logic out of runInference into a new exported
buildInferenceRequest function. This pure builder accepts an optional
fileUriMap (Files API URI path) alongside the existing inline_data fallback,
making it usable by the upcoming runBatchAI batch path without duplicating
Drive-encoding logic.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: replace sequential runBatchAI loop with parallel fetchAll pipeline

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: increase chunk size to 50 rows and update warning dialog for parallel execution

* test: add coverage threshold for files.ts

* fix: use exported mimeType (not Drive native) when uploading Workspace files to Gemini

* test: add missing coverage tests for callGeminiAPIBatch codePairs and drive error branches

* feat: include row range in batch AI progress messages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: add supportsAllDrives=true to Drive API v3 requests

Without this parameter, the Drive REST API silently returns 404 for
files in shared drives (Team Drives), even when the user has access.
DriveApp handles this transparently; raw REST calls do not.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: graceful per-file error handling in Wave 1 pipeline

fetchDriveMetadata, downloadDriveFiles, and uploadFilesToGemini now return
partial results + an errors map instead of throwing on the first failure.
runBatchAI chains the stages so only successfully processed files advance,
and writes [File error: ...] directly to output cells for affected rows
rather than aborting the whole chunk.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: harden Wave 1 error handling and restore single-flush invariant

- uploadFilesToGemini: check getResponseCode() before JSON.parse, add
  try/catch for non-JSON bodies so every failure path sets the errors map
- callGeminiAPIBatch: wrap JSON.parse in try/catch so one malformed
  response body cannot abort the entire batch
- downloadDriveFiles: parse error body for actionable messages, matching
  fetchDriveMetadata behavior
- index.ts: eliminate redundant uploadBytes copy (pass bytes directly),
  clear bytes map after upload to release memory before Wave 2,
  defer file-error cell writes to post-batch loop so the entire chunk
  lands in a single SpreadsheetApp.flush()
- Toast now correctly counts file-error rows in the error tally

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* cleanup

* test(client): add tests for getActiveRangeInfo service

* test(server): add edge-case branch tests for Drive API calls

* docs: add design and plan for coverage threshold fixes

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Three A/B test UX patterns for the document summarization recipe:
V1 (4-button), V2 (2-button simplified), V3 (didactic step-by-step).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@aaronbrezel aaronbrezel merged commit 0b7d1e4 into main May 7, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants